#!/usr/local/python/bin/python
# coding=utf-8
__author__ = 'cz'

import argparse
import sys
import time
import uuid
from datetime import datetime, timedelta
from json import *

from model.AppInfo import *
from model.DbConnInfo import *
from model.DbInfo import *
from model.FileColInfo import FileColInfo
from model.FileInfo import *
from model.FileMetaInfo import FileMetaInfo
from model.Log import *
from tdtools.DcpClient_tdsql_prd import *
from tdtools.DcpException import DcpException
from tdtools.LocalUtil import *
from tdtools.ShellUtil import *
from tdtools.TDSQLCon import TDSQLCon

_bizcode = ''
_bizdate = 0
_starttime = ''

_logger=LogUtil._logger

_dbName = ''
_model = Config.MODEL
_localErrorDir = Config.LOCAL_ERROR_DIR

# 系统系统信息
_appInfoObj = AppInfo()
# 文件基本信息
_fileInfoObj = FileInfo()
# 数据库信息
_dbInfoObj = DbInfo()
# 数据库连接信息
_dbConnInfoObj = DbConnInfo()
# 文件字段信息
_fileColsObj = FileColInfo()

_tDSQLCon=TDSQLCon()
_ERRORCODE = 0
_ROWNUM = 0
_ERROR_MSG = ''
_RESULT = []


# 检查参数(业务编号、业务日期)
def checkArgs(desc='参数检查'):
    global _bizcode,_bizdate,_starttime
    parser = argparse.ArgumentParser(description=desc)
    parser.add_argument('bizcode', help='业务编码')
    parser.add_argument('bizdate', type=int, metavar='yyyymmdd', help='业务日期')
    args = parser.parse_args()

    _bizcode = args.bizcode
    _bizdate = args.bizdate
    _starttime = getCurrTime()

    current_date = datetime.now()
    formatted_date = current_date.strftime('%Y-%m-%d')
    logFile="%s_%s_%s.log"%(_bizcode,_bizdate,formatted_date)
    logPrefix="业务编码：%s 业务日期: %s  脚本执行时间：%s " %(_bizcode,_bizdate,_starttime)
    LogUtil.initLog(logFile, logPrefix)

# 获取参数
def getParam(start=1):
    params = ' '
    if len(sys.argv) > 1:
        params = ' '.join(sys.argv[start:])
    return params


def getCurrTime():
    return time.strftime('%Y-%m-%d %X', time.localtime())


# 初始化文件信息
def initFileInfo():
    global _logPrefix,_fileInfoObj
    client = DcpClient()
    _fileInfo = client.getFileInfo(_bizcode)
    _logger.info(" 基础配置数据:%s \n" % str(_fileInfo))
    if len(_fileInfo) == 0:
        raise DcpException(Config.EXCEPTION_FILE_INFO_NULLT, '获取基础配置数据为空')
    _fileInfoObj.setData(JSONDecoder().decode(_fileInfo))


# 初始化系统信息
def initAppInfo():
    global _appInfoObj
    client = DcpClient()
    _appInfo = client.getAppInfo(_fileInfoObj.getDbCode(), _fileInfoObj.getAppCode())
    _logger.info(" 系统配置数据:%s \n" % str(_appInfo))
    if len(_appInfo) == 0:
        raise DcpException(Config.EXCEPTION_APP_INFO_NULLT, '获取系统配置数据为空')
    _appInfoObj.setData(JSONDecoder().decode(_appInfo))

# 初始化字段信息
def initFileCols():
    global _fileColsObj
    client = DcpClient()
    _fileCols = client.getFileCols(getBizCode())
    if len(_fileCols) == 0:
        raise DcpException(Config.EXCEPTION_FILE_COLS_INFO_NULLT, '获取文件字段配置数据为空')
    _fileColsObj.setData(JSONDecoder().decode(_fileCols))

# 初始化数据库信息
def initDbInfo():
    global _dbInfoObj
    client = DcpClient()
    _dbInfo = client.getDbInfo(_fileInfoObj.getDbCode())
    _logger.info(" 数据库配置数据:%s \n" % str(_dbInfo))
    if len(_dbInfo) == 0:
        raise DcpException(Config.EXCEPTION_APP_INFO_NULLT, '获取数据库配置数据为空')
    _dbInfoObj.setData(JSONDecoder().decode(_dbInfo))
    host = _dbInfoObj.getSqlHost()
    if host in (None, ''):
        raise DcpException(Config.RUNNING_ERROR, 'sqlHost为空')

    port = _dbInfoObj.getSqlPort()
    if port in (None, ''):
        raise DcpException(Config.RUNNING_ERROR, 'sqlPort为空')

    user = _dbInfoObj.getSqlUser()
    if user in (None, ''):
        raise DcpException(Config.RUNNING_ERROR, 'sqlUser为空')

    password = _dbInfoObj.getSqlPwd()
    if password in (None, ''):
        raise DcpException(Config.RUNNING_ERROR, 'sqlPwd为空')



def initTdConnInfo():
    global _dbInfoObj,_tDSQLCon
    host = _dbInfoObj.getSqlHost()
    port = _dbInfoObj.getSqlPort()
    user = _dbInfoObj.getSqlUser()
    password = _dbInfoObj.getSqlPwd()
    dbName = _dbInfoObj.getDbName()
    _tDSQLCon=TDSQLCon(host, port, user, password,dbName)

# 获取业务日期
def getBizDate():
    return str(_bizdate)

# 获取上一天业务日期
def getPreviousDay(dateStr):
    dateObj = datetime.strptime(dateStr, '%Y%m%d')
    previousDay = dateObj - timedelta(days=1)
    return previousDay.strftime('%Y%m%d')

# 获取业务代码
def getBizCode():
    return _bizcode

def getSourceFilePath():
    if not _fileInfoObj.getFilePath() or not _fileInfoObj.getTableName() or not _fileInfoObj.getFileType():
        raise DcpException(Config.RUNNING_ERROR, ' _fileInfoObj中FilePath、TableName、FileType存在空值')
    yesterday = getPreviousDay(str(_bizdate))
    tableName = _fileInfoObj.getTableName()
    if 'ads_' in tableName.lower() or 'ods_' in tableName.lower():
        odsTableName = _fileInfoObj.getTableName().split("_",1)
        tableName = odsTableName[1]
    else:
        tableName = tableName
    _logger.info(_fileInfoObj.getFilePath())
    dataFile =_fileInfoObj.getFilePath()+"/"+tableName+"_"+yesterday+ "."+_fileInfoObj.getFileType()
    _logger.info("载入文件路径：%s" % dataFile)
    return dataFile

def getMetaFilePath():
    yesterday = getPreviousDay(str(_bizdate))
    tableName = _fileInfoObj.getTableName()
    if 'ads_' in tableName:
        odsTableName = _fileInfoObj.getTableName().split("_", 1)
        tableName = odsTableName[1]
    else:
        tableName = tableName
    metaFile =_fileInfoObj.getFilePath()+"/"+tableName+"_"+yesterday+".flg"
    _logger.info("元数据文件路径：%s" % metaFile)
    return metaFile

#获取flg文件里的内容
def getFileMetaInfo(filePath):
    with open(filePath, "r") as f:
        s = f.read()
        #flg文件中内容 
        line = s.strip().split(" ")
        directoty,filename = os.path.split(filePath)

        parts = filename.rsplit('_', 1)
        # parts[0] 是分割后的第一部分，parts[1] 是分割后的第二部分
        tab_name = parts[0]

        if(len(line)!=3):
            #raise ValueError("元数据文件中格式不符合，需要包含表名、文件名、行数")
            raise ValueError("元数据文件中格式不符合，需要包含文件名称、大小、行数")
        # tab_name = line[0]
        # tb_db_name=tab_name.split(".")
        # if len(tb_db_name)!=2:
        #     raise DcpException(Config.RUNNING_ERROR, '元数据文件中需要按照格式：库名.表名')
        file_name = directoty +"/"+ line[0]
        data_line_nums = line[2]
        _fileMetaInfo = FileMetaInfo(tab_name, file_name, data_line_nums)
        _logger.info("元数据文件内容：%s" % _fileMetaInfo)
    return _fileMetaInfo



# 获取文件总行数
def getDataFileLine(filePath):
    f = open(filePath, 'rb')
    res = len(f.readlines())
    f.close()
    return res
    
def extExit(code):
    sys.exit(code)


def exit(code, shellCode, info):
    try:
        execLog(shellCode, code, info, shellCode)
    except Exception as e:
        _logger.error(e, exc_info=True)
        sys.exit(code)



# 执行日志处理
def execLog(shellCode, status, note, bizType):
        log = ExecLog(shellCode, getBizCode(), getBizDate(), getParam(), _starttime, getCurrTime(), status, note,
                      bizType)
        DcpClient.saveExecLog(log)



# 执行日志处理
def log(logLevel, shellCode, logInfo, bizType):
    try:
        if logLevel > Config.CURR_LOGLEVEL:
            return
        print getCurrTime() + ' 信息:' + logInfo + ' 执行脚本:' + shellCode + ' 业务代码:' + getBizCode() + ' 业务日期:' + getBizDate() + ' 业务类型:' + bizType
        log = Log(shellCode, getBizCode(), logInfo, getParam(), getCurrTime(), bizType, getBizDate())
        DcpClient.saveLog(log)
    except Exception as e:
        print("保存详细日志出错！")
        print(e)


def debugLog(logLevel, shell):
    if logLevel > Config.CURR_LOGLEVEL:
        return
    print getCurrTime() + ' 执行:' + shell


# 获取脚本文件的当前路径
# return dirPath
def curFileDir():
    # 获取脚本路径
    path = sys.path[0]
    # 如果是脚本文件，则返回的是脚本的目录；
    # 如果是py2exe编译后的文件，则返回的是编译后的文件路径
    if os.path.isdir(path):
        return path
    elif os.path.isfile(path):
        return os.path.dirname(path)


####### 执行Shell（所有信息都输出到客户端，服务器端只接收出错的简单信息） ######
def execShellToClient(shellCode, shell, msg):
    debugLog(Config.WARN_LEVEL, shell)
    if not ShellUtil.exShell1(shell):
        log(Config.INFO_LEVEL, shellCode, msg + ' 失败', shellCode)
        exit(Config.RUNNING_ERROR, shellCode, msg + ' 失败')
    else:
        log(Config.DEBUG_LEVEL, shellCode, msg + ' 成功', shellCode)


####### 执行Shell（出错的详细信息输出到客户端和服务器端） ######
def execShellToServer(shellCode, shell, msg):
    debugLog(Config.WARN_LEVEL, shell)
    reslt = ShellUtil.exShell2(shell)
    status = reslt[0]
    output = reslt[1]
    if status != 0:
        outputErrorInfo(shellCode, msg, output)
    else:
        log(Config.DEBUG_LEVEL, shellCode, msg + ' 成功', shellCode)


####### 执行Shell ######
def execShell(shellCode, shell, msg):
    if _model == 1 or _model.upper() == 'CLIENT':
        execShellToClient(shellCode, shell, msg)
    elif _model == 2 or _model.upper() == 'SERVER':
        execShellToServer(shellCode, shell, msg)


####### 输出详细信息到控制台和本地文本 ######
def outputErrorInfo(shellCode, msg, output):
    # 创建本地错误信息目录
    shell = LocalUtil.getMkdirShell(_localErrorDir)
    message = '创建' + _localErrorDir + '目录'
    execShell(shellCode, shell, message)
    # 将详细的错误信息输出到本地文本
    localErrorFilePath = _localErrorDir + '/ERROR_' + str(uuid.uuid1())
    message = msg + ' 失败。\n详细错误信息如下：\n' + output
    shell = LocalUtil.getEchoToFileShell(message, localErrorFilePath)
    execShell(shellCode, shell, message)
    # 输出信息到屏幕
    print(message)
    # 输出信息到服务器
    message = 'errorinfo:' + localErrorFilePath
    log(Config.INFO_LEVEL, shellCode, message, shellCode)
    exit(Config.RUNNING_ERROR, shellCode, message)


####### 返回结果信息 ######
def reslt(shellCode, status, msg):
    if status:
        log(Config.INFO_LEVEL, shellCode, msg + ' 失败', shellCode)
        exit(Config.RUNNING_ERROR, shellCode, msg + ' 失败')
    else:
        log(Config.DEBUG_LEVEL, shellCode, msg + ' 成功', shellCode)

